"""
K-means聚类可视化模块
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import io
import base64
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_samples, silhouette_score
import matplotlib.cm as cm
import logging
from matplotlib.font_manager import FontProperties
import platform
import matplotlib

matplotlib.use('Agg')
matplotlib.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS']
matplotlib.rcParams['axes.unicode_minus'] = False


# 根据操作系统设置中文字体
def set_chinese_font():
    system = platform.system()
    if system == 'Windows':
        font_path = 'C:/Windows/Fonts/simhei.ttf'  # Windows 黑体
    elif system == 'Darwin':  # macOS
        font_path = '/System/Library/Fonts/PingFang.ttc'  # macOS 苹方
    else:  # Linux
        font_path = '/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf'  # Linux Droid Sans

    try:
        font = FontProperties(fname=font_path)
        plt.rcParams['font.family'] = font.get_name()
        return font
    except:
        # 如果找不到指定字体，尝试使用系统默认中文字体
        plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS']
        plt.rcParams['axes.unicode_minus'] = False
        return None


# 设置中文字体
chinese_font = set_chinese_font()

# 聚类类别名称映射
CLUSTER_NAMES = {
    0: "经典佳作",
    1: "新锐热门",
    2: "小众精品",
    3: "普通作品",
    4: "待发掘"
}


def generate_kmeans_visualizations(scaled_data: np.ndarray, labels: np.ndarray,
                                   cluster_centers: np.ndarray, numeric_cols: list) -> dict:
    """
    生成K-means聚类的所有可视化图表
    
    Args:
        scaled_data: 标准化后的数据
        labels: 聚类标签
        cluster_centers: 聚类中心
        numeric_cols: 数值型列名列表
        
    Returns:
        dict: 包含所有可视化图表的base64字符串
    """
    try:
        visualizations = {}

        # 1. 散点图
        visualizations['scatter'] = _generate_scatter_plot(scaled_data, labels, cluster_centers)

        # 2. 轮廓图
        visualizations['silhouette'] = _generate_silhouette_plot(scaled_data, labels)

        # 3. 热力图
        visualizations['heatmap'] = _generate_heatmap(cluster_centers, numeric_cols)

        # 4. 雷达图
        visualizations['radar'] = _generate_radar_plot(cluster_centers, numeric_cols)

        return visualizations
    except Exception as e:
        logging.error(f"生成可视化图表时出错: {str(e)}")
        raise


def _generate_scatter_plot(scaled_data: np.ndarray, labels: np.ndarray,
                           cluster_centers: np.ndarray) -> str:
    """生成散点图"""
    pca = PCA(n_components=2)
    reduced = pca.fit_transform(scaled_data)
    centers = pca.transform(cluster_centers)

    plt.figure(figsize=(10, 8))
    scatter = plt.scatter(reduced[:, 0], reduced[:, 1], c=labels, cmap='viridis')
    plt.scatter(centers[:, 0], centers[:, 1], c='red', marker='x', s=200,
                linewidths=3, label='聚类中心')

    plt.title('电影数据聚类分析结果', fontsize=14, fontproperties=chinese_font)
    plt.xlabel('主成分1 (PC1)', fontsize=12, fontproperties=chinese_font)
    plt.ylabel('主成分2 (PC2)', fontsize=12, fontproperties=chinese_font)

    legend_labels = [CLUSTER_NAMES.get(i, f'聚类 {i}') for i in range(len(np.unique(labels)))]
    legend1 = plt.legend(scatter.legend_elements()[0], legend_labels,
                         title="聚类类型", loc="upper right", prop=chinese_font)
    plt.gca().add_artist(legend1)
    plt.legend(loc="upper left", prop=chinese_font)

    # colorbar
    cb = plt.colorbar()
    cb.set_label('聚类', fontproperties=chinese_font)
    for l in cb.ax.get_yticklabels():
        l.set_fontproperties(chinese_font)

    return _save_figure_to_base64()


def _generate_silhouette_plot(scaled_data: np.ndarray, labels: np.ndarray) -> str:
    """生成轮廓图"""
    try:
        # 确保数据格式正确
        if not isinstance(scaled_data, np.ndarray):
            scaled_data = np.array(scaled_data)
        if not isinstance(labels, np.ndarray):
            labels = np.array(labels)

        # 计算轮廓系数
        silhouette_avg = silhouette_score(scaled_data, labels)
        sample_silhouette_values = silhouette_samples(scaled_data, labels)

        # 创建图形
        plt.figure(figsize=(10, 8))

        # 获取唯一的标签值
        unique_labels = np.unique(labels)
        n_clusters = len(unique_labels)

        y_lower = 10
        for i in unique_labels:
            # 获取当前聚类的轮廓值
            cluster_silhouette_values = sample_silhouette_values[labels == i]
            cluster_silhouette_values.sort()

            size_cluster_i = len(cluster_silhouette_values)
            y_upper = y_lower + size_cluster_i

            # 使用颜色映射
            color = cm.nipy_spectral(float(i) / n_clusters)

            # 绘制轮廓图
            plt.fill_betweenx(np.arange(y_lower, y_upper),
                              0, cluster_silhouette_values,
                              facecolor=color, edgecolor=color, alpha=0.7)

            # 添加聚类标签
            plt.text(-0.05, y_lower + 0.5 * size_cluster_i,
                     CLUSTER_NAMES.get(int(i), f'聚类 {i}'),
                     fontproperties=chinese_font)

            y_lower = y_upper + 10

        # 添加平均轮廓系数线
        plt.axvline(x=silhouette_avg, color="red", linestyle="--")

        # 设置图形标题和标签
        plt.title('聚类轮廓分析图', fontsize=14, fontproperties=chinese_font)
        plt.xlabel('轮廓系数', fontsize=12, fontproperties=chinese_font)
        plt.ylabel('聚类', fontsize=12, fontproperties=chinese_font)

        # 设置y轴范围
        plt.ylim([0, len(scaled_data) + (n_clusters + 1) * 10])

        # 设置x轴范围
        plt.xlim([-0.1, 1])

        return _save_figure_to_base64()

    except Exception as e:
        logging.error(f"生成轮廓图时出错: {str(e)}")
        raise


def _generate_heatmap(cluster_centers: np.ndarray, numeric_cols: list) -> str:
    """生成热力图"""
    plt.figure(figsize=(12, 8))
    cluster_centers_df = pd.DataFrame(cluster_centers, columns=numeric_cols)
    sns.heatmap(cluster_centers_df, cmap='YlOrRd', annot=True, fmt='.2f')
    plt.title('聚类中心特征热力图', fontsize=14, fontproperties=chinese_font)
    plt.xlabel('特征', fontsize=12, fontproperties=chinese_font)
    plt.ylabel('聚类', fontsize=12, fontproperties=chinese_font)

    return _save_figure_to_base64()


def _generate_radar_plot(cluster_centers: np.ndarray, numeric_cols: list) -> str:
    """生成雷达图"""
    plt.figure(figsize=(10, 10))
    n_features = min(5, len(numeric_cols))
    important_features = numeric_cols[:n_features]

    angles = np.linspace(0, 2 * np.pi, n_features, endpoint=False).tolist()
    angles += angles[:1]  # 闭合图形

    ax = plt.subplot(111, polar=True)
    for i in range(len(cluster_centers)):
        values = cluster_centers[i][:n_features].tolist()
        values += values[:1]  # 闭合图形
        ax.plot(angles, values, linewidth=2, label=CLUSTER_NAMES.get(i, f'聚类 {i}'))
        ax.fill(angles, values, alpha=0.1)

    plt.xticks(angles[:-1], important_features, fontproperties=chinese_font)
    plt.title('聚类特征雷达图', fontsize=14, fontproperties=chinese_font)
    plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1), prop=chinese_font)

    return _save_figure_to_base64()


def _save_figure_to_base64() -> str:
    """将当前图形保存为base64字符串"""
    buf = io.BytesIO()
    plt.savefig(buf, format='png', bbox_inches='tight', dpi=300)
    plt.close()
    buf.seek(0)
    return base64.b64encode(buf.read()).decode()
